package org.swxjava.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.swxjava.locator.ServiceLocator;
import org.swxjava.util.BeanUtils;
import org.swxjava.util.Log;
import org.swxjava.util.LogFactory;
import org.swxjava.util.MessageBundle;

public class DefaultServiceLocatorManager implements ServiceLocatorManager {

	private static final Log LOG = LogFactory.getLog(DefaultServiceLocatorManager.class);

    /**
     * The list of the locator types
     */
    private Map<String, Class> locatorTypes = new HashMap<String, Class>();

    /**
     * The list of the locators
     */
    private Map<String, ServiceLocator> services = new HashMap<String, ServiceLocator>();
    
	
	public void addServiceLocatorType(String id, String className) {
		Class locatorType = BeanUtils.getClassForName(className);
    	if(locatorType != null) {
	    	if(BeanUtils.isImplements(locatorType, ServiceLocator.class)) {
	            if (LOG.isDebugEnabled()) {
	            	LOG.debug("- adding locator: " + id + " = " + className);
	            }
	            locatorTypes.put(id, locatorType);
	    	} else {
	    		LOG.warn("The service locator class [" + className + "] does not implement ServiceLocator. id=" + id);
	    	}
    	}
	}

	public void addService(String serviceName, String typeName, Map params) throws InstantiationException, IllegalAccessException,IllegalArgumentException {
		Class locatorType = locatorTypes.get(typeName);
		if(locatorType == null) {
			String errorMsg = "Could not find the service locator named : " + typeName;
			LOG.error(errorMsg);
			throw new IllegalArgumentException(errorMsg);
		}
		ServiceLocator locator = (ServiceLocator) locatorType.newInstance();
		if(params != null) {
			for(Iterator<Map.Entry> it = params.entrySet().iterator(); it.hasNext();) {
				Map.Entry entry = it.next();
				String name = (String) entry.getKey();
				String value = (String) entry.getValue();
				try {
					BeanUtils.setProperty(locator, name, value);
				} catch (IllegalArgumentException e) {
					LOG.warn("The locator does not allow parameter named : " + name);
				}
			}
		}
		addService(serviceName, locator);
	}

	public void addService(String serviceName, ServiceLocator locator)
			throws IllegalArgumentException {
		if(services.containsKey(serviceName)) {
			throw new IllegalArgumentException(MessageBundle.getString("SwxMessage.DuplicateName", serviceName));
		}
        if(LOG.isDebugEnabled()) {
        	LOG.debug("- adding service: " + serviceName + " with " + locator.getClass().getSimpleName());
        }
		// TODO Should I test locator class?
		services.put(serviceName, locator);
	}

	public ServiceLocator getServiceLocator(String serviceName) {
		ServiceLocator locator = services.get(serviceName);
		if(locator == null) {
			LOG.warn("Could not find the service locator by service name:" + serviceName);
		}
		return locator;
	}
	
	public List<String> getServiceNames() {
		List<String> serviceNames = new ArrayList<String>();
		for(Iterator<Map.Entry<String, ServiceLocator>> it = services.entrySet().iterator(); it.hasNext();) {
			Map.Entry<String, ServiceLocator> entry = it.next();
			serviceNames.add(entry.getKey());
		}
		return serviceNames;
	}
}